package com.mornd.storage.service.impl;

import com.mornd.storage.config.MinioConfigProperties;
import com.mornd.storage.service.FileStorageService;
import io.minio.*;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * @author: mornd
 * @dateTime: 2023/8/1 - 22:51
 */

public class MinioFileStorageServiceImpl implements FileStorageService {
    @Resource
    private MinioClient minioClient;
    @Resource
    private MinioConfigProperties minIOConfigProperties;

    private final static String SEPARATOR = "/";

    /**
     * @param prefix
     * @param filename
     * @return prefix/yyyy/MM/dd/filename
     */
    private String builderFilePath(String prefix, String filename) {
        StringBuilder stringBuilder = new StringBuilder(50);
        if (StringUtils.hasText(prefix)) {
            stringBuilder.append(prefix).append(SEPARATOR);
        }
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");
        String datePrefix = LocalDateTime.now().format(formatter);
        stringBuilder.append(datePrefix).append(SEPARATOR);
        stringBuilder.append(filename);
        return stringBuilder.toString();
    }

    /**
     * 拼接完整 url 路径
     *
     * @param filePath
     * @return
     */
    private String buildUrlPath(String filePath) {
        StringBuilder urlPath = new StringBuilder(minIOConfigProperties.getReadPath());
        urlPath.append(SEPARATOR).append(minIOConfigProperties.getBucket());
        urlPath.append(SEPARATOR).append(filePath);
        return urlPath.toString();
    }

    /**
     * 上传
     *
     * @param prefix
     * @param filename
     * @param contentType
     * @param inputStream
     * @return
     */
    @Override
    public String upload(String prefix, String filename, String contentType, InputStream inputStream) throws Exception {
        String filePath = builderFilePath(prefix, filename);

        PutObjectArgs putObjectArgs = PutObjectArgs.builder()
                .object(filePath)
                .contentType(contentType)
                .bucket(minIOConfigProperties.getBucket())
                .stream(inputStream, inputStream.available(), -1)
                .build();

        ObjectWriteResponse objectWriteResponse = minioClient.putObject(putObjectArgs);
        return buildUrlPath(filePath);
    }

    @Override
    public String upload(String prefix, String filename, MultipartFile file) throws Exception {
        try(InputStream inputStream = file.getInputStream()) {
            return this.upload(prefix, filename, file.getContentType(), inputStream);
        }
    }

    /**
     * 删除文件
     *
     * @param pathUrl 文件全路径
     */
    @Override
    public void delete(String pathUrl) throws Exception {
        String key = pathUrl.replace(minIOConfigProperties.getReadPath() + "/", "");
        String bucket = minIOConfigProperties.getBucket();
        if (!key.startsWith(bucket)) {
            return;
        }
        String filePath = key.substring(bucket.length() + 1);

        RemoveObjectArgs removeObjectArgs = RemoveObjectArgs.builder().bucket(bucket).object(filePath).build();
        minioClient.removeObject(removeObjectArgs);
    }

    /**
     * 下载文件
     *
     * @param pathUrl 文件全路径
     * @return
     */
    @Override
    public byte[] download(String pathUrl) throws Exception {
        String key = pathUrl.replace(minIOConfigProperties.getReadPath() + "/", "");
        String bucket = minIOConfigProperties.getBucket();
        if (!key.startsWith(bucket)) {
            return null;
        }
        String filePath = key.substring(bucket.length() + 1);
        InputStream inputStream = null;
        inputStream = minioClient.getObject(GetObjectArgs.builder().bucket(bucket).object(filePath).build());

        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        byte[] buff = new byte[100];
        int rc = 0;
        while (true) {
            try {
                if (!((rc = inputStream.read(buff, 0, 100)) > 0)) break;
            } catch (IOException e) {
                e.printStackTrace();
            }
            byteArrayOutputStream.write(buff, 0, rc);
        }

        try {
            inputStream.close();
        } catch (Exception e) {
        }

        try {
            byteArrayOutputStream.close();
        } catch (Exception e) {
        }
        return byteArrayOutputStream.toByteArray();
    }
}
